@page "/file-upload"

@using System 
@using System.IO
@using Microsoft.AspNetCore.Hosting
@using Microsoft.Extensions.Logging
@inject ILogger<Index> Logger
@inject IWebHostEnvironment Environment
@inject IJSRuntime JS
@inject NavigationManager NavigationManager
@using Microsoft.JSInterop 
@using BlazorApp4.Data
@inject DaprClient daprClient;

@implements IAsyncDisposable

<p>
    <label>
        单个文件最大长度:
        <input type="number" @bind="maxFileSize" />
    </label>
</p>

<p>
    <label>
        最大上传文件数量:
        <input type="number" @bind="maxAllowedFiles" />
    </label>
</p>

<div @ref="fileDropContainer" class="file-drop-zone @HoverClass" @ondragenter="OnDragEnter" @ondragleave="OnDragLeave" @ondragover="OnDragEnter">
    <InputFile  OnChange="@OnChange"  @ref="inputFile"   multiple />
</div>

<p style="color:red"> @errorMessage </p>

@if (isLoading)
{
    <p>Progress: @string.Format("{0:P0}", progressPercent)</p>
}
@if (loadedFiles == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
      <thead>
        <tr>
          <th>文件名</th>
          <th>上传文件者ip</th>
          <th>文件长度</th>
          <th>文件上传时间</th>
        </tr>
      </thead>
      @foreach (var file in loadedFiles)
      {
        <CurrentFile FileInfoAttr=file DownLoadFile="@(() => DownloadFileFromURL(file))"/>
      }
  </table>
}

@code {
    private List<FileDetail> loadedFiles = new List<FileDetail>();
    //文件上传相关
    ElementReference fileDropContainer;
    private String HoverClass;
    InputFile inputFile;
    private long maxFileSize = 1024 * 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool isLoading;
    private decimal progressPercent;
    private Object m_obj = new object();

    private string? errorMessage = null;
    const string DAPR_STATE_STORE = "statestore";
    const string DAPR_ALL_FILE = "all_files";

    protected override void OnInitialized()
    {
        base.OnInitialized();
    }
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        loadedFiles = await daprClient.GetStateAsync<List<FileDetail>>(DAPR_STATE_STORE, DAPR_ALL_FILE);
        if (loadedFiles == null)
        {
            loadedFiles = new List<FileDetail>();

        }
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
        }
    }


    private void OnDragEnter(DragEventArgs e) => HoverClass = "hover";

    private void OnDragLeave(DragEventArgs e) => HoverClass = string.Empty;

    async Task OnChange(InputFileChangeEventArgs e)
    {
        Console.WriteLine("当前taskid" + Thread.CurrentThread.ManagedThreadId);
        isLoading = false;
        var ip = await GetIpAddress();
        progressPercent = 0;
        if (e.FileCount > maxAllowedFiles) {
            errorMessage = "您上传的文件数量超过了最大数量，可修改最大上传文件数量";
        } else {
            errorMessage = null;
            var files = e.GetMultipleFiles(maxAllowedFiles);
            foreach (var file in files)
            {
                if (file.Size > maxFileSize)
                {
                    errorMessage = "文件长度超过最大限制，可修改最大文件长度";
                    break;
                } else
                {
                    errorMessage = null;
                }
            }

            if (errorMessage == null)
            {
                isLoading = true;
                foreach (var file in files)
                {
                    try
                    {
                        var trustedFileName = file.Name;
                        string json;
                        var path = Path.Combine(Environment.WebRootPath, "files", trustedFileName);
                        if (File.Exists(path)) {
                            loadedFiles.Remove(loadedFiles.Where(info => info.Name == trustedFileName).FirstOrDefault());
                            await daprClient.SaveStateAsync(DAPR_STATE_STORE, DAPR_ALL_FILE, loadedFiles);
                        }
                        await using FileStream writeStream = new(path, FileMode.Create);
                        var readStream = file.OpenReadStream(maxFileSize);
                        var bytesRead = 0;
                        var totalRead = 0;
                        var buffer = new byte[1024 * 30];

                        while ((bytesRead = await readStream.ReadAsync(buffer)) != 0)
                        {
                            totalRead += bytesRead;
                            await writeStream.WriteAsync(buffer, 0, bytesRead);
                            progressPercent = Decimal.Divide(totalRead, file.Size);
                            StateHasChanged();
                        }
                        FileDetail fileDetail = new FileDetail();
                        fileDetail.Name = file.Name;
                        fileDetail.Ip = ip;
                        fileDetail.Length = file.Size;
                        fileDetail.UploadTime = DateTimeOffset.Now.ToString();
                        loadedFiles.Add(fileDetail);
                        loadedFiles = loadedFiles.OrderByDescending(o => Convert.ToDateTime(o.UploadTime)).ToList();
                        await daprClient.SaveStateAsync(DAPR_STATE_STORE, DAPR_ALL_FILE, loadedFiles);
                    }
                    catch (Exception ex)
                    {                 
                        Logger.LogError("File: {Filename} Error: {Error}", 
                            file.Name, ex.Message);
                    }
                }       
            }
        }
        isLoading = false;
        Console.WriteLine("Finish load");
  
    }

    private async Task DownloadFileFromURL(FileDetail  file)
    {
        var uri = NavigationManager.BaseUri;
        await JS.InvokeVoidAsync("triggerFileDownload",  file.Name, uri);
    }

    public async Task<String> GetIpAddress()
    {
            try
            {
                var ipAddress = await JS.InvokeAsync<string>("getIpAddress")
                    .ConfigureAwait(true);
                return ipAddress;
            }
            catch(Exception e)
            {
                //If your request was blocked by CORS or some extension like uBlock Origin then you will get an exception.
                return string.Empty;
            }
    }

    public async ValueTask DisposeAsync()
    {

    }
}
